﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using System.Data.Services.Common;
using System.Collections;

namespace Azure.TableQuery.Core
{
    public class StorageClientExtensionQueryBuilder
    {
        private const string EntityFormat = @"
public class {0} : TableServiceEntity
{{
    {1}
}}";

        private const string EntityQueryFormat = @"
public XTableServiceQuery<{0}> {0}
    {{
        get
        {{
            return this.CreateQuery<{0}>(""{0}"");
        }}
    }}";

        private const string ContextFormat = @"
{0}

public class {1}Context : XTableServiceContext, IAzureTableQuery
{{
    public {1}Context(string baseAddress, StorageCredentials credentials)
            : base(baseAddress, credentials)
    {{ 
        //this.MergeOption = MergeOption.NoTracking;
    }}

    {2}
    
    public void OutputToGrid(DataGrid grid)
    {{
        var query = {3};

        if (query == null)
        {{
            grid.Visible = false;
            return;
        }}

        if (query.GetType().GetInterfaces().Length > 0)
        {{
            BindArray(query, grid);
        }}
        else
        {{
            CreateAndBindArray(query, grid);
        }}
        
        grid.DataBind();
    }}

    // Hack
    private void CreateAndBindArray(object single, DataGrid grid)
    {{
        var itemList = new ArrayList();

        if (single != null)
        {{
            itemList.Add(single);
        }}
        
        grid.DataSource = itemList;
    }}

    // Hack
    private void BindArray(object list, DataGrid grid)
    {{
        var itemList = new ArrayList();
        
        if (list != null)
        {{
            try
            {{
                foreach(var item in (IEnumerable)list)
                {{
                    itemList.Add(item);
                }}        
            }}
            catch {{ }}
        }}
        grid.DataSource = itemList;
    }}

    public MemoryStream OutputToXml(bool compress)
    {{
        return null;        
    }}  
}}

public class QueryContextFactory : IQueryContextFactory
{{
    public IAzureTableQuery CreateQueryContext(string baseAddress, StorageCredentials credentials)
    {{
        return new {1}Context(baseAddress, credentials);
    }}
}}
";
        private const string PropertyFormat = @"
public {0} {1} {{ get; set; }}
";

        private StringBuilder builder = new StringBuilder();
        public void AddQuery(List<GenericEntity> entities, string queryText)
        {
            // Build the entities and the query lines
            StringBuilder entitybuilder = new StringBuilder();
            StringBuilder entityQueryBuilder = new StringBuilder();
            foreach (var entity in entities)
            {
                entitybuilder.Append(BuildEntity(entity));
                entityQueryBuilder.Append(BuildEntityQuery(entity));
            }
            
            System.Diagnostics.Trace.WriteLine(" Query: " + queryText);
            
            builder.AppendFormat(ContextFormat,
                entitybuilder.ToString(),
                GetEntityNames(entities),                
                entityQueryBuilder.ToString(),
                queryText);
            
        }

        private string GetEntityNames(List<GenericEntity> entities)
        {
            string names = entities[0].GetTableName();

            for (int i = 1; i < entities.Count; i++)
            {
                names += entities[i].GetTableName();
            }

            return names;
        }
        public string BuildEntityQuery(GenericEntity entity)
        {
            return string.Format(EntityQueryFormat, entity.GetTableName());
        }

        public string BuildEntity(GenericEntity entity)
        {
            StringBuilder properties = new StringBuilder();
            var props = entity.GetProperties();
            foreach (var key in props.Keys)
            {
                if (key != "PartitionKey"
                    && key != "RowKey"
                    && key != "Timestamp")
                {
                    properties.AppendFormat(PropertyFormat,
                        props[key].FullName.ToString(),
                        key);
                }
            }
            
            return string.Format(EntityFormat,
                    entity.GetTableName(),
                    properties.ToString());
        }

        public override string ToString()
        {
            return builder.ToString();
        }
    }
}

